package com.edu.system.service.analysis.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson2.JSON;
import com.edu.system.domain.Student;
import com.edu.system.domain.StudentTag;
import com.edu.system.domain.TClass;
import com.edu.system.domain.TStudyScore;
import com.edu.system.domain.vo.AvgExamSchoolRankVO;
import com.edu.system.domain.vo.ClassTopStudentSummary;
import com.edu.system.domain.vo.ClassTopStudentSummary.LessionTopNum;
import com.edu.system.domain.vo.ClassTopStudentSummary.TitleTopNum;
import com.edu.system.domain.vo.CountStudentExamVO;
import com.edu.system.domain.vo.TotalScoreVO;
import com.edu.system.mapper.StudentTagMapper;
import com.edu.system.mapper.TStudyScoreMapper;
import com.edu.system.service.IStudentService;
import com.edu.system.service.IStudentTypeService;
import com.edu.system.service.ITClassService;
import com.edu.system.service.ITStudyScoreService;
import com.edu.system.service.analysis.AnalysisService;
import com.edu.system.service.analysis.StudentTagKeys;

import lombok.extern.slf4j.Slf4j;

/**
 * @author huangc
 *
 */
@Slf4j
@Component("analysisService")
public class AnalysisServiceImpl implements AnalysisService {

	@Autowired
	private ITStudyScoreService studyScoreService;
	@Autowired
	private TStudyScoreMapper studyScoreMapper;
	
	@Autowired
	private StudentTagMapper studentTagMapper;
	
	@Autowired
	private ITClassService classService;
	@Autowired
	private IStudentTypeService studentTypeService;

	@Autowired
	private IStudentService studentService;

	@Override
	public Map<String, Object> getSingleStudentData(String stuNo) {

//		List<String> lessons = studyScoreService.queryLessonsByEduId(stuNo);
//		lessons.remove("总分");

		List<TStudyScore> scoreList = studyScoreService.selectScoreList(TStudyScore.builder().stuNo(stuNo).build());

		scoreList = scoreList.stream().filter(score -> score.getTitle().matches(".*(期中|期末).*"))
				.filter(score -> score.getScore() > 0)//.filter(score -> !"总分".equals(score.getLessonName()))
				.collect(Collectors.toList());

		Map<String, Date> titleMap = new HashMap<String, Date>();

		Map<String, List<TStudyScore>> lessionMap = new HashMap<String, List<TStudyScore>>();
		for (TStudyScore stc : scoreList) {
			String less = stc.getLessonName();
			String title = stc.getTitle();
			if (!lessionMap.containsKey(less)) {
				lessionMap.put(less, new LinkedList<TStudyScore>());
			}
			lessionMap.get(less).add(stc);
			if (!titleMap.containsKey(title)) {
				titleMap.put(title, stc.getExamDate());
			}
		}
//		ArrayList<Map.Entry<String, Date>> list = new ArrayList<Entry<String, Date>>(titleMap.entrySet());
//		Collections.sort(list, (a, b) -> {
//			return b.getValue().compareTo(a.getValue());
//		});

		List<String> titles = new ArrayList<String>();
		titles.addAll(titleMap.keySet());
		titles = titles.stream().sorted(Comparator.comparing(String::toString, (s1, s2) -> {
			return compare(s1, s2);
		})).collect(Collectors.toList());
		
		for (String less : lessionMap.keySet()) {
			List<TStudyScore> scors = lessionMap.get(less);
			lessionMap.put(less, scors.stream().sorted(Comparator.comparing(TStudyScore::getTitle, (s1, s2) -> {
				return compare(s1, s2);
			})).collect(Collectors.toList()));
		}
		List<String> lessons = new ArrayList<String>(lessionMap.keySet());

		Map<String, Object> result = new HashMap<String, Object>();
		result.put("lessons", lessons);
		result.put("titles", titles);
		result.put("datas", lessionMap);
		return result;
	}

	@Override
	public Map<String, Object> getSingleStudentRadarData(String stuNo) {
		Map<String, Object> result = new HashMap<String, Object>();

		List<AvgExamSchoolRankVO> scores = studyScoreService.queryLastTwoLessonsByEduId(stuNo);
		if (null != scores && scores.size() > 0) {
			scores = scores.stream().filter(score -> score.getRankSchool() > 0)
					.filter(score -> !"总分".equals(score.getLessonName())).collect(Collectors.toList());

			Map<String, Integer> datas = scores.stream()
					.collect(Collectors.toMap(AvgExamSchoolRankVO::getLessonName, AvgExamSchoolRankVO::getRankSchool));

			List<String> examIds = Arrays.asList(scores.get(0).getExamIds().split(","));
			Map<String, Object> params = new HashMap<String, Object>();
			params.put("examIds", examIds);
			List<CountStudentExamVO> nums = studyScoreMapper.countExamStuNum(params);
			Map<String, Integer> titles = new HashMap<String, Integer>();

			for (CountStudentExamVO row : nums) {
				if ("总分".equals(row.getLessonName()) || !datas.containsKey(row.getLessonName()))
					continue;
				if (titles.containsKey(row.getLessonName())) {
					titles.put(row.getLessonName(), Math.max(titles.get(row.getLessonName()), row.getStuNum()));
				} else {
					titles.put(row.getLessonName(), row.getStuNum());
				}
			}
			result.put("titles", titles);
			result.put("datas", datas);
		}
		return result;
	}

	@Override
	public List<String> getStudentTags(String stuNo) {

		List<String> result = new ArrayList<String>();
		
		List<StudentTag> tags = studentTagMapper.selectStudentTagList(StudentTag.builder().stuNo(stuNo).isDeleted(0).build());
		
		if(null == tags || tags.isEmpty()) {
			return result;
		}
		Map<String , StudentTag> maps = new HashMap<String , StudentTag>();
		for(StudentTag tag : tags) {
			String tagGroup = tag.getTagGroup();
			String tagName = tag.getTagName();
			if(maps.containsKey(tagGroup)) {
				if(tag.getPriority() < maps.get(tagGroup).getPriority()) {
					maps.put(tagGroup, tag);
					result.remove(maps.get(tagGroup).getTagName());
					result.add(tagName);
				}
			}else {
				maps.put(tagGroup, tag);
				result.add(tagName);
			}
		}
		return result;
	}

	@Override
	public Map<String, Object> getHonorsClassAvgScore(String cohort) {
		List<TClass> honorsClass = classService.getHonorsClassByCohort(cohort);

		Map<Long, String> classNameMap = honorsClass.stream().collect(Collectors.toMap(TClass::getId, TClass::getName));
		List<Long> classIds = honorsClass.stream().map(TClass::getId).collect(Collectors.toList());

		// 总分
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("classIds", classIds);
		params.put("lessonName", "总分");
		List<TotalScoreVO> scores = studyScoreMapper.getTotalScoreByClass(params);

		scores = scores.stream().filter(score -> score.getTitle().matches(".*(期中|期末).*"))
				.sorted(Comparator.comparing(TotalScoreVO::getTitle, (s1, s2) -> {
					return compare(s1, s2);
				})).collect(Collectors.toList());
		
		List<String> titleMap = new ArrayList<String>();
		Map<String, List<TotalScoreVO>> classMap = new HashMap<String, List<TotalScoreVO>>();

		for (TotalScoreVO stc : scores) {
			String className = classNameMap.get(stc.getClassId());
			if (!classMap.containsKey(className)) {
				classMap.put(className, new ArrayList<TotalScoreVO>());
			}
			stc.setTotalScore(stc.getTotalScore() / stc.getStuNum());
			classMap.get(className).add(stc);

			String title = stc.getTitle();
			if (!titleMap.contains(title)) {
				titleMap.add(title);
			}
		}
		List<String> titles = titleMap.stream().sorted(Comparator.comparing(String::toString, (s1, s2) -> {
			return compare(s1, s2);
		})).collect(Collectors.toList());

		Map<String, Object> result = new HashMap<String, Object>();
		result.put("oclass", classNameMap.values());
		result.put("titles", titles);
		result.put("datas", classMap);

		return result;
	}

	@Override
	public Map<String, ClassTopStudentSummary> getHonorsClassTopStudentSummary(String cohort) {
		Map<String, ClassTopStudentSummary> classMappingData = new HashMap<String, ClassTopStudentSummary>();

		List<TClass> honorsClass = classService.getHonorsClassByCohort(cohort);
		if (null == honorsClass || honorsClass.size() < 1)
			return classMappingData;

		Map<Long, String> classNameMap = honorsClass.stream().collect(Collectors.toMap(TClass::getId, TClass::getName));
		List<Long> classIds = honorsClass.stream().map(TClass::getId).collect(Collectors.toList());
		// 总分参考人数
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("classIds", classIds);
		params.put("lessonName", "总分");
		List<CountStudentExamVO> nums = studyScoreMapper.countExamStuNum(params);
		nums = nums.stream().filter(num -> "总分".equals(num.getLessonName()))
				.filter(num -> num.getTitle().matches(".*(期中|期末).*")).collect(Collectors.toList());

		if (null == nums || nums.size() < 1)
			return classMappingData;

		Map<String, Integer> examStuNumMap = new HashMap<String, Integer>();
		for (CountStudentExamVO row : nums) {
			if (examStuNumMap.containsKey(row.getTitle())) {
				examStuNumMap.put(row.getTitle(), Math.max(examStuNumMap.get(row.getTitle()), row.getStuNum()));
			} else {
				examStuNumMap.put(row.getTitle(), row.getStuNum());
			}
		}

		List<String> examIds = nums.stream().map(CountStudentExamVO::getExamId).collect(Collectors.toList());
		params.put("examIds", examIds);
		List<TStudyScore> total = studyScoreMapper.getHonorsClassTopStudentSummary(params);

		// className->title-<num
		Map<String, List<TStudyScore>> titleMapTop20 = new HashMap<String, List<TStudyScore>>();
		Map<String, List<TStudyScore>> titleMapTop50 = new HashMap<String, List<TStudyScore>>();
		for (TStudyScore row : total) {
			String title = row.getTitle();
			String className = classNameMap.get(row.getClassId());

			if (!classMappingData.containsKey(className)) {
				classMappingData.put(className, new ClassTopStudentSummary());
				classMappingData.get(className).setClassId(row.getClassId());
				classMappingData.get(className).setClassName(className);
				classMappingData.get(className).setTitles(new HashMap<String, TitleTopNum>());
			}
			if (!classMappingData.get(className).getTitles().containsKey(title)) {
				classMappingData.get(className).getTitles().put(title, TitleTopNum.builder().title(title).build());

			}
			TitleTopNum titelTopNum = classMappingData.get(className).getTitles().get(title);
			// 初始化
			if (!titleMapTop20.containsKey(title)) {
				titleMapTop20.put(title, new ArrayList<TStudyScore>());
			}
			if (!titleMapTop50.containsKey(title)) {
				titleMapTop50.put(title, new ArrayList<TStudyScore>());
			}
			// 赋值
			if (titleMapTop20.get(title).size() <= (examStuNumMap.get(title) * 0.2)) {
				titleMapTop20.get(title).add(row);
				titelTopNum.setTop20Num(titelTopNum.getTop20Num() + 1);
			}
			if (titleMapTop50.get(title).size() <= (examStuNumMap.get(title) * 0.5)) {
				titleMapTop50.get(title).add(row);
				titelTopNum.setTop50Num(titelTopNum.getTop50Num() + 1);
			}
		}
		for (String key : classMappingData.keySet()) {
			List<String> sorted = classMappingData.get(key).getTitles().keySet().stream()
					.sorted(Comparator.comparing(String::toString, (s1, s2) -> {
						return compare(s1, s2);
					})).collect(Collectors.toList());
			Map<String, TitleTopNum> newTitles = new LinkedHashMap<String, TitleTopNum>(); 
			sorted.forEach(row ->{
				newTitles.put(row, classMappingData.get(key).getTitles().get(row));
			});
			classMappingData.get(key).setTitles(newTitles);
		}
		return classMappingData;
	}

	public Map<String, Object> getTopStudentSummaryByClass(long classId) {
		TClass oclass = classService.selectTClassById(classId);
		oclass.setName(classService.joinClassName(oclass));

		List<TClass> honorsClass = classService.getHonorsClassByCohort(oclass.getCohort());

		Map<Long, String> classNameMap = honorsClass.stream().collect(Collectors.toMap(TClass::getId, TClass::getName));

		List<Long> classIds = honorsClass.stream().map(TClass::getId).collect(Collectors.toList());

		// 参考人数
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("classIds", classIds);
		List<CountStudentExamVO> nums = studyScoreMapper.countExamStuNum(params);

		nums = nums.stream().filter(num -> !"总分".equals(num.getLessonName()))
				.filter(num -> num.getTitle().matches(".*(期中|期末).*")).collect(Collectors.toList());

		Map<String, Map<String, Integer>> examStuNumMap = new HashMap<String, Map<String, Integer>>();
		for (CountStudentExamVO row : nums) {
			if (!examStuNumMap.containsKey(row.getTitle())) {
				examStuNumMap.put(row.getTitle(), new HashMap<String, Integer>());
			}
			examStuNumMap.get(row.getTitle()).put(row.getLessonName(), row.getStuNum());
		}

		List<String> examIds = nums.stream().map(CountStudentExamVO::getExamId).collect(Collectors.toList());
		params.put("examIds", examIds);
		// 两班明细
		List<TStudyScore> total = studyScoreMapper.getHonorsClassTopStudentSummary(params);
		total = total.stream().filter(num -> !"总分".equals(num.getLessonName())).collect(Collectors.toList());

		// {label:"数学",colsKey:"key"}
		List<String> lessons = new ArrayList<String>();
		for (String tit : examStuNumMap.keySet()) {
			lessons = new ArrayList<String>(examStuNumMap.get(tit).keySet());
			break;
		}

		Map<String, ClassTopStudentSummary> classMappingData = new HashMap<String, ClassTopStudentSummary>();

		// className->title->lesson-<num
		Map<String, Map<String, List<TStudyScore>>> titleMapTop20 = new HashMap<String, Map<String, List<TStudyScore>>>();
		Map<String, Map<String, List<TStudyScore>>> titleMapTop50 = new HashMap<String, Map<String, List<TStudyScore>>>();
		for (TStudyScore row : total) {
			String title = row.getTitle();
			String lesson = row.getLessonName();
			String className = classNameMap.get(row.getClassId());

			if (!classMappingData.containsKey(className)) {
				classMappingData.put(className, ClassTopStudentSummary.builder().classId(row.getClassId())
						.className(className).titles(new HashMap<String, TitleTopNum>()).build());
			}
			ClassTopStudentSummary classSummary = classMappingData.get(className);

			if (!classSummary.getTitles().containsKey(title)) {
				classSummary.getTitles().put(title,
						TitleTopNum.builder().title(title).lessons(new HashMap<String, LessionTopNum>()).build());
			}

			TitleTopNum titleTop = classSummary.getTitles().get(title);
			if (!titleTop.getLessons().containsKey(lesson)) {
				titleTop.getLessons().put(lesson, LessionTopNum.builder().lesson(lesson).totalStuNum(examStuNumMap.get(title).get(lesson)).build());
			}

			LessionTopNum lessonTopNum = titleTop.getLessons().get(lesson);

			// 初始化
			if (!titleMapTop20.containsKey(title)) {
				titleMapTop20.put(title, new HashMap<String, List<TStudyScore>>());
				titleMapTop20.get(title).put(lesson, new ArrayList<TStudyScore>());
			}
			if (!titleMapTop20.get(title).containsKey(lesson)) {
				titleMapTop20.get(title).put(lesson, new ArrayList<TStudyScore>());
			}
			if (!titleMapTop50.containsKey(title)) {
				titleMapTop50.put(title, new HashMap<String, List<TStudyScore>>());
				titleMapTop50.get(title).put(lesson, new ArrayList<TStudyScore>());
			}
			if (!titleMapTop50.get(title).containsKey(lesson)) {
				titleMapTop50.get(title).put(lesson, new ArrayList<TStudyScore>());
			}
			// 赋值
			if (titleMapTop20.get(title).get(lesson).size() <= (examStuNumMap.get(title).get(lesson) * 0.2)) {
				titleMapTop20.get(title).get(lesson).add(row);
				lessonTopNum.setTop20Num(lessonTopNum.getTop20Num() + 1);
				
			}
			if (titleMapTop50.get(title).get(lesson).size() <= (examStuNumMap.get(title).get(lesson) * 0.5)) {
				titleMapTop50.get(title).get(lesson).add(row);
				lessonTopNum.setTop50Num(lessonTopNum.getTop50Num() + 1);
			}
		}
		ClassTopStudentSummary summary = classMappingData.get(oclass.getName());
		
		List<String> sorted = summary.getTitles().keySet().stream()
				.sorted(Comparator.comparing(String::toString, (s1, s2) -> {
					return compare(s1, s2);
				})).collect(Collectors.toList());
		Map<String, TitleTopNum> newTitles = new LinkedHashMap<String, TitleTopNum>(); 
		sorted.forEach(row ->{
			newTitles.put(row, summary.getTitles().get(row));
		});
		summary.setTitles(newTitles);
		
		Map<String, Object> result = new HashMap<String, Object>();
		result.put("lessons", lessons);
		result.put("datas", summary);
		
		return result;
	}

	public int compare(String s1, String s2) {
		if (s1 == null || s2 == null || s1.length() < 14 || s2.length() < 14) {
			return 0;
		}
		Map<String , Integer> levelMap = new HashMap<String,Integer>();
		levelMap.put("一", 1);
		levelMap.put("二", 2);
		levelMap.put("三", 3);
		
		int co2 = Integer.parseInt(s2.substring(0, 4));
		int co1 = Integer.parseInt(s1.substring(0, 4));
		if (co2 != co1) {
			return co2 - co1;
		} else {
			String level2 = s2.substring(6, 7);
			String level1 = s1.substring(6, 7);
			if (!level1.equals(level2)) {
				
				return levelMap.get(level1).compareTo(levelMap.get(level2));
			} else {
				String st2 = s2.substring(7, 8);
				String st1 = s1.substring(7, 8);
				if (!st2.equals(st1)) {
					return st1.compareTo(st2);
				} else {
					String m2 = s2.substring(11, 12);
					String m1 = s1.substring(11, 12);
					return m1.compareTo(m2);
				}
			}
		}
	}

	/**
	 * task tigger
	 */
	@Override
	public void analysisStudentTags() {
		log.info("===========start init student tags task =============");
		Map<String , Object> contextData = new HashMap<String ,Object>();
		contextData.put("studentScoreDetails", this.getHonorsClassScore(null));
		contextData.put("exameStudentNums", this.getClassExamStudentNums(null));
		contextData.put("honorsClassExameStudentNums", this.getClassExamStudentNums(this.getHonorsClassIds(null)));
		List<StudentTag> insertDatas = new ArrayList<StudentTag>(); 
		for(StudentTagKeys tag : StudentTagKeys.values()) {
			Map<String ,StudentTagKeys> tagMap = tag.invoke(contextData);
			for(String stuNo : tagMap.keySet()) {
				StudentTagKeys rowtag = tagMap.get(stuNo);
				insertDatas.add(StudentTag.builder()
						.stuNo(stuNo)
						.tagKey(rowtag.getKey())
						.tagName(rowtag.getName())
						.tagGroup(rowtag.getGroup())
						.priority(rowtag.getPriority()).build());
			}
		}
		int r = studentTagMapper.batchInsert(insertDatas);
		log.info("init student tags r:" + r);
	}
	
	private List<Long> getHonorsClassIds(String cohort){
		List<TClass> honorsClass = classService.getHonorsClassByCohort(cohort);
		List<Long> classIds = honorsClass.stream().map(TClass::getId).collect(Collectors.toList());
		return classIds;
	}
	
	private List<TStudyScore> getHonorsClassScore(String cohort) {
		List<Long> classIds  = this.getHonorsClassIds(cohort);
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("classIds", classIds);
		List<TStudyScore> details = studyScoreMapper.getHonorsClassTopStudentSummary(params);
		return details;
	}
	
	private List<CountStudentExamVO> getClassExamStudentNums(List<Long> classIds) {
		
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("classIds", classIds);
		List<CountStudentExamVO> nums = studyScoreMapper.countExamStuNum(params);
		return nums;
	}
	
	

}
